package com.wlb365.doc.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wlb365.common.util.UploadUtil;
import com.wlb365.doc.bean.HttpTool;
import com.wlb365.doc.cfca.APIUtils;
import com.wlb365.doc.cfca.RSAP7SignatureUtils;
import com.wlb365.doc.sign.ApiException;
import com.wlb365.doc.sign.ApiSignature;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 概述：沙箱环境
 * </p>
 *
 * @author zwh
 * @version 1.0
 * @copyRight 北京微利宝信息技术有限公司  All right reserved.
 * @date 2020/3/21
 */
@Slf4j
@RestController
@RequestMapping("sandbox")
public class SandboxController {

    @Value("${api.url-sandbox}")
    private String url;
    static HttpTool httpTool = null;

    static {
        HttpTool.HttpToolConfig config = new HttpTool.HttpToolConfig();
        config.setConnectTimeoutSeconds(40);
        config.setReadTimeoutSeconds(40);
        config.setWriteTimeoutSeconds(40);
        httpTool = new HttpTool(config);
    }

    @RequestMapping("/test")
    public SandboxResult proxy(
            @RequestParam String appId
            , @RequestParam String privateKey
            , @RequestParam String cerPath
            , @RequestParam String cerPwd
            , @RequestParam String method
            , @RequestParam String version
            , @RequestParam String bizContent
            , @RequestParam(defaultValue = "get") String httpMethod
            , @RequestParam(defaultValue = "false") boolean isDownloadRequest
            , HttpServletRequest request
            , HttpServletResponse response
    ) throws ApiException {

        Assert.isTrue(StringUtils.isNotBlank(appId), "AppId不能为空");
        Assert.isTrue(StringUtils.isNotBlank(privateKey), "PrivateKey不能为空");
        Assert.isTrue(StringUtils.isNotBlank(method), "method不能为空");

        // 公共请求参数
        String traceId = UUID.randomUUID().toString().replace("-", "");
        Map<String, String> params = new HashMap<String, String>();
        params.put("app_id", appId);
        params.put("trace_id", traceId);
        params.put("method", method);
        params.put("format", "json");
        params.put("charset", "utf-8");
        params.put("sign_type", "MD5RSA"); //MD5RSA或RSA2或RSA
        params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        params.put("version", version);

        // 业务参数
        params.put("data", bizContent);

        Map<String, Object> signs = new HashMap<>();
        //微利宝签名
        String content = ApiSignature.getSignStr(traceId, bizContent, appId);
        try {
            System.out.println("待签名内容：" + content);
            String gyl_WLB_SIGN = ApiSignature.md5RSA(content, privateKey, "utf-8");
            System.out.println("微利宝签名(gyl_WLB_SIGN)：" + gyl_WLB_SIGN);
            signs.put("gyl_WLB_SIGN", gyl_WLB_SIGN);

            //资金方签名，未上送cerPath||cerPwd不进行资方签名
            if (StringUtils.isNotBlank(cerPath) && StringUtils.isNotBlank(cerPwd)) {
                String signData = APIUtils.joinSignData(traceId, bizContent, appId);
                String gyl_F_SIGN = RSAP7SignatureUtils.sign(cerPath, cerPwd, signData);
                signs.put("gyl_F_SIGN", gyl_F_SIGN);
                System.out.println("资金方签名(gyl_F_SIGN)：" + gyl_F_SIGN);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("构建签名失败");
        }


        SandboxResult result = new SandboxResult();

        result.params = buildParamQuery(params);

        result.beforeSign = content;
        result.signs = JSONObject.toJSONString(signs);

        //签名
        params.put("signs", JSON.toJSONString(signs));

        Collection<MultipartFile> uploadFiles = UploadUtil.getUploadFiles(request);
        List<HttpTool.UploadFile> files = uploadFiles.stream()
                .map(multipartFile -> {
                    try {
                        return new HttpTool.UploadFile(multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getBytes());
                    } catch (IOException e) {
                        log.error("封装文件失败", e);
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        try {
            String responseData;
            if (isDownloadRequest) {
                Response resp = httpTool.requestForResponse(url, params, Collections.emptyMap(), HttpTool.HTTPMethod.GET);
                Headers respHeaders = resp.headers();
                ResponseBody body = resp.body();
                if (body == null) {
                    return null;
                }
                respHeaders
                        .names()
                        .forEach(name -> response.setHeader(name, respHeaders.get(name)));

                IOUtils.copy(body.byteStream(), response.getOutputStream());
                response.flushBuffer();
                return null;
            } else if (!CollectionUtils.isEmpty(files)) {
                responseData = httpTool.requestFileString(url, params, Collections.emptyMap(), files);
            } else {
                responseData = httpTool.request(url, params, Collections.emptyMap(), HttpTool.HTTPMethod.fromValue(httpMethod));
            }
            log.info("返回结果：{}", responseData);
            result.apiResult = responseData;

            return result;
        } catch (Exception e) {
            log.error("请求失败", e);
            throw new RuntimeException("请求失败");
        }
    }

    @Data
    public static class SandboxResult {
        private String params;
        private String beforeSign;
        private String signs;

        private String apiResult;
    }

    @Data
    public static class Signs {
        /**
         * 资金方签名
         */
        private String gyl_F_SIGN;
        /**
         * 微利宝平台签名
         */
        private String gyl_WLB_SIGN;
    }


    /**
     * 发送get请求
     *
     * @param url
     * @return JSON或者字符串
     * @throws Exception
     */
    public static String get(String url, Map<String, String> params) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            List<NameValuePair> nameValuePairs = params.entrySet()
                    .stream()
                    .map(entry -> new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())))
                    .collect(Collectors.toList());
            /**
             * 包装成一个Entity对象
             */
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
            //参数转换为字符串
            String paramsStr = EntityUtils.toString(entity);
            url = url + "?" + paramsStr;
            /**
             * 创建一个post对象
             */
            HttpGet get = new HttpGet(url);

            /**
             * 执行post请求
             */
            response = httpClient.execute(get);
            /**
             * 通过EntityUitls获取返回内容
             */
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(httpClient);
            IOUtils.closeQuietly(response);
        }
        return null;
    }

    protected String buildParamQuery(Map<String, String> params) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());
        }
        return sb.toString().substring(1);
    }
}
